#include "../include/filetree.h"
#include "../include/node.h"
#include "../include/extfsdll.h"
#include "../include/macro_file_type.h"
#include "../include/macro_str.h"
#include "../include/macro_signal.h"
#include "../include/macro_constant.h"
#include "../include/macro_gui_str.h"
#include "../include/nodearray.h"
#include <QStringList>
#include <QString>
#include <QChar>
#include <QComboBox>
#include <QEvent>
#include <QKeyEvent>
#include <QPushButton>
void FileTree::setWidgets(QTreeWidget* tree,QComboBox* path,QComboBox* fs,QPushButton* go)
{
	tree_widget=tree;
	combo_box_file_path=path;
	combo_box_fs=fs;
	combo_box_file_path->setMaxCount(COMBO_BOX_MAX_COUNT);
	combo_box_file_path->installEventFilter(this);
	pushButton_go=go;
	pushButton_go->installEventFilter(this);
}
void FileTree::init()
{
	disk_count=ExtFsDLL::diskCount();
	disk_nodes=new Node[disk_count];
	partition_nodes=new Node*[disk_count];
	for(uint32 i=0;i<disk_count;i++)
	{
		disk_nodes[i].setDiskNodeData(DISK_STR+QString::number(i),STR_SLASH+QString::number(i)+STR_SLASH);
		tree_widget->addTopLevelItem(disk_nodes+i);
		addDefaultNodeFor(disk_nodes+i);
		uint32 partition_count=ExtFsDLL::partitionCount(i);
		partition_nodes[i]=new Node[partition_count];
		for(uint32 j=0;j<partition_count;j++)
			setFsName(i,j);
	}
}
void FileTree::expandNode(Node* dir)
{
	removeDefaultNodeFor(dir);
	if(dir->parent()==NULL)
	{
		expandDiskNode(dir);
		return;
	}
	if(dir->isPathEmpty())
		dir->setPath(static_cast<Node*>(dir->parent())->path());
	emit iNeedNodeArray(*dir,FILETREE_NODEARRAY);
}
void FileTree::listSubDir(const Node& dir,const NodeArray* node_array,uint32 file_tree_flag)
{
	if(file_tree_flag!=FILETREE_NODEARRAY)
		return;
	Node* expanding_node=&const_cast<Node&>(dir);
	expanding_node->setNodeArray(const_cast<NodeArray*>(node_array));
#ifdef CHECK_DIR_EMPTY
	expanding_node->setNodeArrayRef();
	uint32 disk_index=expanding_node->path().section(CH_SLASH,1,1).toInt();
	uint32 fs_index=expanding_node->path().section(CH_SLASH,2,2).toInt();
#endif
	for(uint32 i=FILE_START_INDEX;i<node_array->nodeCount();i++)
	{
		if(node_array->at(i)->type()==DIR_ENTRY_FILE_TYPE_DIR)
		{
#ifdef CHECK_DIR_EMPTY
			if(ExtFsDLL::isHaveSubDir(disk_index,fs_index,node_array->at(i)->inodeNum()))
				addDefaultNodeFor(node_array->at(i));
#else
			addDefaultNodeFor(node_array->at(i));
#endif
			expanding_node->addChild(node_array->at(i));
		}
	}
#ifndef CHECK_DIR_EMPTY
	if(expanding_node->childCount()!=0)
		expanding_node->setNodeArrayRef();
	else
		expanding_node->setNodeArray(NULL);
#endif
}
void FileTree::listAllFileToFileList(Node* dir) const
{
	if(dir->parent()==NULL)
		return;
	if(dir->isPathEmpty())
		dir->setPath(static_cast<Node*>(dir->parent())->path());
	emit iNeedNodeArray(*dir,FILELIST_NODEARRAY);
}
void FileTree::listAllFileToFileList(const QString& path) const
{
	emit iNeedNodeArray(path,FILELIST_NODEARRAY);
}
void FileTree::collapseNode(Node* dir)
{
	removeNodeTree(dir);
	if(dir->parent()!=NULL)
		dir->cancelNodeArrayRef();
	dir->setNodeArray(NULL);
	addDefaultNodeFor(dir);
}
void FileTree::removeNodeTree(Node* dir)
{
	while(dir->childCount()!=0)
	{
		Node* removing_node=static_cast<Node*>(dir->child(0));
		if(!removing_node->isNodeArrayNull())
		{
			removeNodeTree(removing_node);
			removing_node->cancelNodeArrayRef();
			removing_node->setNodeArray(NULL);
		}
		else
			removeDefaultNodeFor(removing_node);
		dir->takeChild(0);
	}
}
void FileTree::collapseAllNode()
{
	for(uint32 i=0;i<disk_count;i++)
		removeNodeTree(disk_nodes+i);
}
void FileTree::expandDiskNode(Node* disk)
{
	uint32 disk_index=tree_widget->indexOfTopLevelItem(disk);
	uint32 partition_count=ExtFsDLL::partitionCount(disk_index);
	for(uint32 i=0;i<partition_count;i++)
	{
		disk_nodes[disk_index].addChild(partition_nodes[disk_index]+i);
		addDefaultNodeFor(partition_nodes[disk_index]+i);
	}
}
FileTree::~FileTree()
{
	for(uint32 i=0;i<disk_count;i++)
		delete[] partition_nodes[i];
	delete[] partition_nodes;
	delete[] disk_nodes;
}
void FileTree::addDefaultNodeFor(Node* dir){dir->addChild(new Node);}
void FileTree::removeDefaultNodeFor(Node* dir){delete dir->takeChild(0);}
void FileTree::setFsName(uint32 disk_index,uint32 fs_index)
{
	QString name=QString::fromUtf16(ExtFsDLL::fsName(disk_index,fs_index));
	QString real_name=name.section(STR_SLASH,0,0);
	QString disk_num=name.section(STR_SLASH,1,1);
	QString disk_type=name.section(STR_SLASH,2,2);
	static uint32 i=1;
	if(name.isEmpty())
		real_name=UNKNOWN_DISK;
	else if(real_name.isEmpty())
	{
		if(disk_num=="EXT")
		{
			real_name=EXT_DISK;
			real_name+="[";
			real_name+=QString::number(i);
			real_name+="]";
			combo_box_fs->addItem(real_name);
			i++;
		}
		else if(!disk_num.isEmpty())
		{
			if(disk_type=="2")
				real_name+=REMOVABLE_DISK;
			else if(disk_type=="3")
				real_name=NATIVE_DISK;
			real_name+="(";
			real_name+=disk_num;
			real_name+=":";
			real_name+=")";
		}
	}
	else
	{
		if(disk_num!="EXT")
		{
			real_name+="(";
			real_name+=disk_num;
			real_name+=":";
			real_name+=")";
		}
		else
		{
			real_name+="[";
			real_name+=QString::number(i);
			real_name+="]";
			combo_box_fs->addItem(real_name);
			i++;
		}
	}
	partition_nodes[disk_index][fs_index].setRootNodeData(real_name,disk_nodes[disk_index].path()+QString::number(fs_index)+STR_SLASH);
}
bool FileTree::eventFilter(QObject* obj,QEvent* event_)
{
	if(obj==combo_box_file_path&&event_->type()==QEvent::KeyRelease)
	{
		if(static_cast<QKeyEvent*>(event_)->key()==Qt::Key_Return)
		{
			QString path=findFsIndex(combo_box_fs->currentText())+combo_box_file_path->currentText().section(STR_SLASH,1,-1);
			if(path[path.size()-1]!=QChar(CH_SLASH))
				path+=STR_SLASH;
			emit iNeedNodeArray(path,FILELIST_NODEARRAY);
			return true;
		}
	}
	else if(obj==pushButton_go&&event_->type()==QEvent::MouseButtonRelease)
	{
		QString path=findFsIndex(combo_box_fs->currentText())+combo_box_file_path->currentText().section(STR_SLASH,1,-1);
		if(path[path.size()-1]!=QChar(CH_SLASH))
			path+=STR_SLASH;
		emit iNeedNodeArray(path,FILELIST_NODEARRAY);
		return false;
	}
	return false;
}
const QString& FileTree::findFsIndex(const QString& fs_name) const
{
	uint32 disk_count=ExtFsDLL::diskCount();
	for(uint32 i=0;i<disk_count;i++)
	{
		uint32 patition_count=ExtFsDLL::partitionCount(i);
		for(uint32 j=0;j<patition_count;j++)
			if(partition_nodes[i][j].text(0)==fs_name)
				return partition_nodes[i][j].path();
	}
}
void FileTree::showPathInComboBox(const QString& path)
{
	uint32 disk_index=path.section(STR_SLASH,1,1).toInt();
	uint32 fs_index=path.section(STR_SLASH,2,2).toInt();
	combo_box_fs->setCurrentIndex(combo_box_fs->findText(partition_nodes[disk_index][fs_index].text(0)));
	combo_box_file_path->setEditText(STR_SLASH+path.section(STR_SLASH,3,-1));
}